package net.lab1024.sa.admin.module.business.traffic.aibi.service;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import jakarta.annotation.Resource;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import net.lab1024.sa.admin.module.business.traffic.config.AibiCameraProperties;
import net.lab1024.sa.base.common.domain.ResponseDTO;
import net.lab1024.sa.base.module.support.config.ConfigKeyEnum;
import net.lab1024.sa.base.module.support.config.ConfigService;
import net.lab1024.sa.base.module.support.traffic.domain.dto.MqttResponseDTO;
import net.lab1024.sa.base.module.support.traffic.domain.form.TrafficLaneModeForm;
import net.lab1024.sa.base.module.support.traffic.service.TrafficControlService;

/**
 * 基于比例阈值的车道模式切换服务
 */
@Slf4j
@Service
public class AibiLaneModeService {

    @Resource
    private AibiCameraProperties aibiCameraProperties;

    @Resource
    private TrafficControlService trafficControlService;

    @Resource
    private ConfigService configService;

    @Resource
    private AibiCameraStatusService cameraStatusService;

    private final Map<String, LaneState> laneStateMap = new ConcurrentHashMap<>();

    /**
     * 评估比例并决定是否调整车道模式
     *
     * @param cameraCode 摄像机编号
     * @param ratio 左转/直行排队比值
     * @param sampleTime 数据采集时间
     */
    public void evaluateAndSwitch(String cameraCode, double ratio, LocalDateTime sampleTime) {
        double switchThreshold = resolveSwitchThreshold();
        double revertThreshold = switchThreshold * Math.max(0D, aibiCameraProperties.getMode().getRevertFactor());
        String congestionMode = aibiCameraProperties.getMode().getCongestionMode();
        String defaultMode = aibiCameraProperties.getMode().getDefaultMode();

        LaneState laneState = laneStateMap.computeIfAbsent(cameraCode, key -> new LaneState(defaultMode));
        LocalDateTime now = LocalDateTime.now();
        if (!laneState.allowSwitch(now, aibiCameraProperties.getMode().getMinimumHoldSeconds())) {
            if (log.isDebugEnabled()) {
                log.debug("摄像机[{}] 模式保持期内，跳过切换", cameraCode);
            }
            return;
        }

        String expectedMode = laneState.getCurrentMode();
        if (ratio >= switchThreshold) {
            expectedMode = congestionMode;
        } else if (ratio <= revertThreshold) {
            expectedMode = defaultMode;
        } else {
            // 在阈值区间内保持当前模式
            return;
        }

        if (Objects.equals(expectedMode, laneState.getCurrentMode())) {
            return;
        }

        dispatchLaneMode(cameraCode, expectedMode, laneState, now);
    }

    private void dispatchLaneMode(String cameraCode, String targetMode, LaneState laneState, LocalDateTime dispatchTime) {
        TrafficLaneModeForm form = new TrafficLaneModeForm();
        form.setDeviceRoad(aibiCameraProperties.getDevice().getRoadCode());
        form.setDeviceId(aibiCameraProperties.getDevice().getDeviceId());
        form.setTargetMode(targetMode);

        ResponseDTO<MqttResponseDTO> responseDTO = trafficControlService.setLaneMode(form);

        if (!responseDTO.getOk()) {
            log.warn("下发车道模式失败 camera={}, targetMode={}, msg={}", cameraCode, targetMode, responseDTO.getMsg());
            cameraStatusService.updateLaneMode(cameraCode, targetMode, null, "FAILED", responseDTO.getMsg(), dispatchTime);
            return;
        }

        MqttResponseDTO response = responseDTO.getData();
        String finalMode = targetMode;
        if (response != null && StringUtils.isNotBlank(response.getCurrentMode())) {
            finalMode = response.getCurrentMode();
        }
        laneState.setCurrentMode(finalMode);
        laneState.setLastSwitchTime(dispatchTime);

        String status = response == null ? "SUCCESS" : response.getStatus();
        String message = response == null ? "成功" : response.getMessage();
        String requestId = response == null ? null : response.getRequestId();

        cameraStatusService.updateLaneMode(cameraCode, finalMode, requestId, status, message, dispatchTime);
        log.info("下发车道模式成功 camera={}, targetMode={}, status={}", cameraCode, finalMode, status);
    }

    private double resolveSwitchThreshold() {
        String configValue = configService.getConfigValue(ConfigKeyEnum.PROPORTION_SWITCH_THRESHOLD);
        if (StringUtils.isNotBlank(configValue)) {
            try {
                return Double.parseDouble(configValue);
            } catch (NumberFormatException ex) {
                log.warn("配置 proportion_switch_threshold 数值异常: {}", configValue);
            }
        }
        return aibiCameraProperties.getDefaultThreshold();
    }

    @Data
    private static class LaneState {
        private String currentMode;
        private LocalDateTime lastSwitchTime;

        LaneState(String currentMode) {
            this.currentMode = currentMode;
        }

        boolean allowSwitch(LocalDateTime now, long minimumHoldSeconds) {
            if (lastSwitchTime == null) {
                return true;
            }
            Duration duration = Duration.between(lastSwitchTime, now);
            return duration.getSeconds() >= minimumHoldSeconds;
        }
    }
}

